/* Expression.cs -- 
   Copyright (C) 2007, 2008 Casey Marshall.
   Copyright (C) 2008 Pacific Biosciences, Inc.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */


using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace SexpSharp
{
    /// <summary>
    /// An expression.
    /// </summary>
    public abstract class Expression : ICloneable
    {
		/// <summary>
		/// Return the list containing this expression, if this expression
		/// is a member of a list. Otherwise, returns null.
		/// </summary>
		public List Parent
		{
			get
			{
				return this.parent;
			}
		}

		/// <summary>
		/// Return the next expression, if this expression is a member of
		/// a list, and is not the end of the list. Otherwise, returns
		/// null.
		/// </summary>
		public Expression Next
		{
			get
			{
				return this.next;
			}
		}

		/// <summary>
		/// Return the previous expression, if this expression is a member
		/// of a list, and is not the head of the list. Otherwise, returns
		/// null.
		/// </summary>
		public Expression Previous
		{
			get
			{
				return this.previous;
			}
		}

		/// <summray>
		/// The synchronization object.
		/// </summary>
		public virtual object SyncRoot
		{
			get { return this; }
		}

		/// <summary>
		/// Write this expression in its verbatim representation to the
		/// given stream.
		/// </summary>
		/// <param name="o">The writable stream to write to.</param>
		public abstract void WriteVerbatim(Stream o);

		public void Write(Stream o, Format format)
		{
			switch (format)
			{
			case Format.Verbatim:
				WriteVerbatim(o);
				break;

			case Format.Advanced:
				byte[] b = new UTF8Encoding().GetBytes(ToAdvancedString());
				o.Write(b, 0, b.Length);
				break;

			case Format.Transport:
				// XXX this is just verbatim, base-64 encoded.
				throw new NotImplementedException();
			}
		}

		public abstract string ToAdvancedString();

		public virtual object Clone()
		{
			throw new NotSupportedException();
		}

        public string GetHashString()
        {
            return GetHashString("Sha1");
        }

        public string GetHashString(string hashName)
        {
            byte[] hash = GetHash(hashName);
            StringBuilder str = new StringBuilder();
            foreach (byte b in hash)
                str.Append(b.ToString("x2"));
            return str.ToString();
        }

        public byte[] GetHash()
        {
            return GetHash("Sha1");
        }

		public byte[] GetHash(string hashName)
		{
			MemoryStream s = new MemoryStream();
			WriteVerbatim(s);
			return HashAlgorithm.Create(hashName).ComputeHash(s.GetBuffer());
		}

		protected Expression()
		{
			parent = null;
			next = null;
			previous = null;
		}

		internal List parent;
		internal Expression next;
		internal Expression previous;
    }
}